﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using Cms.Data;
using Cms.Domain;
using Cms.Domain.Comparers;
using Cms.Domain.RepositoryInterfaces;
using iLib.Web.UI;
using SortDirection = Cms.Domain.SortDirection;

namespace Cms.Web.Framework.Controls
{
    public class CategorySelector : Control, INamingContainer
    {
        // Controls
        private IList<Category> _categories;
        private bool _categoriesAreSet;
        private IList<Category> _inheritedCategories;
        private int _offsetLeft;
        private int _offsetTop;
        private IList<Category> _rootCategories;
        private bool _showTabOverlay;
        private Button btnSelect;
        private HtmlInputHidden hidSelectedValues;

        public CategorySelector()
        {
            _offsetTop = -2;
            _offsetLeft = -15;
        }

        //Properties
        public bool ShowTabOverlay
        {
            get { return _showTabOverlay; }
            set { _showTabOverlay = value; }
        }
        
        public int OffsetTop
        {
            get { return _offsetTop; }
            set { _offsetTop = value; }
        }
        
        public int OffsetLeft
        {
            get { return _offsetLeft; }
            set { _offsetLeft = value; }
        }

         public void SetCategories(IList<Category> rootCategories, IList<Category> inheritedCategories, IList<Category> categories)
        {
            _rootCategories = rootCategories;
            _inheritedCategories = inheritedCategories;
            _categories = categories;
            _categoriesAreSet = true;
        }
        
        public IEnumerable<Category> GetSelectedCategories()
        {
            return _categories;
        }
        
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (_categoriesAreSet)
                return;
            _rootCategories = ViewState["RootCategories"] == null
                                  ? new List<Category>()
                                  : IDsToCategories(ViewState["RootCategories"].ToString());
            _inheritedCategories = ViewState["InheritedCategories"] == null
                                       ? new List<Category>()
                                       : IDsToCategories(ViewState["InheritedCategories"].ToString());
            _categories = ViewState["Categories"] == null
                              ? new List<Category>()
                              : IDsToCategories(ViewState["Categories"].ToString());
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            btnSelect = new Button();
            btnSelect.Click += btnSelect_Click;
            btnSelect.Text = "Select";
            btnSelect.Attributes.CssStyle.Add("position", "absolute");
            btnSelect.Attributes.CssStyle.Add("left", "-10000px");
            Controls.Add(btnSelect);
            hidSelectedValues = new HtmlInputHidden();
            Controls.Add(hidSelectedValues);
            string script = "function CollectSelectedCategories(popupID, hidID) {" +
                            "var inputs = document.getElementById(popupID).getElementsByTagName('input');" +
                            "var ids = '';" +
                            "for (var i = 0; i < inputs.length; i++) {" +
                            "if (inputs[i].checked) {" +
                            "if (ids != '') " +
                            "ids += ',';" +
                            "ids += inputs[i].value;" +
                            "}" +
                            "}" +
                            "document.getElementById(hidID).value = ids;" +
                            "}";
            ClientScriptProxy.Current.RegisterClientScriptBlock(this, Page.GetType(), "CategorySelector", script, true);
        }
        
        protected void btnSelect_Click(object sender, EventArgs e)
        {
            // Collect IDs from comma-separated string stored in hidden input
            IList<int> ids = new List<int>();
            foreach (string id in hidSelectedValues.Value.Split(",".ToCharArray()))
            {
                if (id != string.Empty)
                    ids.Add(int.Parse(id));
            }

            // Add categories
            IPageRepository pageRepository = new PageRepository();
            foreach (int id in ids)
            {
                Category category = pageRepository.GetCategory(id);
                if (!_categories.Contains(category) && !_inheritedCategories.Contains(category))
                    _categories.Add(category);
            }

            // Remove categories
            int i = 0;
            while (i < _categories.Count)
            {
                if (ids.Contains(_categories[i].ID))
                {
                    i++;
                    continue;
                }
                _categories.RemoveAt(i);
            }
        }
        
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            string selectedCategories = string.Empty;
            List<Category> allSelectedCategories = _inheritedCategories.ToList();
            allSelectedCategories.AddRange(_categories.Where(c => !_inheritedCategories.Contains(c)));
            allSelectedCategories.Sort(new CategoryNameComparer(SortDirection.Ascending));
            foreach (Category c in allSelectedCategories)
            {
                if (selectedCategories != string.Empty)
                    selectedCategories += ", ";
                if (_inheritedCategories.Contains(c))
                    selectedCategories += "<span class=\"inheritedCategory\">" + c.Name + "</span>";
                else
                    selectedCategories += c.Name;
            }
            if (selectedCategories == string.Empty)
                selectedCategories = "No categories selected.";
            string link = @"<a onclick=""cms.Lists.ShowPopup(document.getElementById('" + ClientID +
                          @"_popup'), this, 'left', " + _offsetLeft + ", " + _offsetTop +
                          @", true, event); iLib.Dom.PreventBubble(event);"" href=""javascript:void(0);"">Select categories</a>";
            Controls.Add(new LiteralControl(selectedCategories + "<br/>" + link));

            string popup = @"<div id=""" + ClientID +
                           @"_popup"" class=""popup"" onclick=""iLib.Dom.PreventBubble(event);""><div class=""popupMenuTop""><div class=""popupMenuTopBg"">&nbsp;</div>"
                           +
                           @"<div class=""popupMenuTopLeftCorner"">&nbsp;</div><div class=""popupMenuTopRightCorner"">&nbsp;</div>"
                           + @"</div><div class=""popupMenu""><div class=""popupMenuLeftBg"">&nbsp;</div>"
                           +
                           @"<div class=""popupMenuRightBg"">&nbsp;</div><div class=""popupMenuContentNoGutter""><div style=""margin: 8px;margin-top:4px;"">";

            IList<Category> itemTree = new List<Category>();
            RenderItems(ref itemTree, _rootCategories);
            foreach (Category c in itemTree)
            {
                popup += @"<div style=""margin-left:" + (c.GetLevelInTree() * 16) + @"px;""><input type=""checkbox""";
                if (_inheritedCategories.Contains(c) || _categories.Contains(c))
                    popup += " checked";
                if (_inheritedCategories.Contains(c))
                    popup += " disabled";
                popup += @" value=""" + c.ID + @"""/><span>" + c.Name + "</span></div>";
            }
            Controls.Add(new LiteralControl(popup));

            popup =
                @"<div class=""horizontalDivider"" style=""margin-bottom: 3px; margin-top: 4px; margin-left: 0px; margin-right: 0px;""></div>" +
                @"<a href=""javascript:void(0);"" onclick=""";
            if (_showTabOverlay)
                popup += "cms.Edit.ShowTabOverlays();";
            popup += "CollectSelectedCategories('" + ClientID + "_popup', '" + hidSelectedValues.ClientID + "');" +
                     "document.getElementById('" + btnSelect.ClientID +
                     @"').click();""><img src=""Admin/Img/icons/accept.png"" /><span>Select</span></a>";
            Controls.Add(new LiteralControl(popup));

            popup = @"</div></div></div><div class=""popupMenuBottom""><div class=""popupMenuBottomBg"">&nbsp;</div>"
                    +
                    @"<div class=""popupMenuBottomLeftCorner"">&nbsp;</div><div class=""popupMenuBottomRightCorner"">&nbsp;</div>"
                    + @"</div></div>";
            Controls.Add(new LiteralControl(popup));
            ViewState["RootCategories"] = CategoriesToIDs(_rootCategories);
            ViewState["InheritedCategories"] = CategoriesToIDs(_inheritedCategories);
            ViewState["Categories"] = CategoriesToIDs(_categories);
        }

        private void RenderItems(ref IList<Category> itemTree, IList<Category> items)
        {
            if (items.Count == 0)
                return;
            foreach (Category mi in items)
            {
                itemTree.Add(mi);
                RenderItems(ref itemTree, mi.SubCategories);
            }
        }
        
        private string CategoriesToIDs(IEnumerable<Category> categories)
        {
            string ids = string.Empty;
            foreach (Category c in categories)
            {
                if (ids != string.Empty)
                    ids += ",";
                ids += c.ID;
            }
            return ids;
        }
        
        private IList<Category> IDsToCategories(string ids)
        {
            IList<Category> categories = new List<Category>();
            if (string.IsNullOrEmpty(ids))
                return categories;
            IPageRepository pageRepository = new PageRepository();
            foreach (string id in ids.Split(",".ToCharArray()))
                categories.Add(pageRepository.GetCategory(int.Parse(id)));
            return categories;
        }
    }
}